﻿using System;
using System.Collections.Generic;
using System.Text;
using RS.DOM.Common;


namespace RS.DOM.Types
{
    public class Collection : Token
    {
        public Collection(Context context)
            : base(context)
        {
            base.TokenType = TokenType.Collection;
            this.Result = new List<Token>();
        }

        public override Token Operation(Token token, OperationType type)
        {
            if (type == OperationType.Agregate)
            {
                return this.Agregate(token);
            }
            else if (type == OperationType.Add)
            {
                return this.Add(token);
            }
            else if (type == OperationType.AddApply)
            {
                return this.AddApply(token);
            }
            else if (type == OperationType.Point)
            {
                return this.Point(token);
            }
            else if (type == OperationType.Devide)
            {
                return this.Devide(token);
            }
            else
            {
                return base.Operation(token, type);
            }
        }

        public Token Agregate(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Operator)
            {
                if (token.Text == "*")
                {
                    if (this.Result.Count > 0)
                    {
                        result = this.Result[0];
                        for (int i = 1; i < this.Result.Count; i++)
                        {
                            result = result.Operation(this.Result[i], OperationType.Multiply);
                        }
                    }
                }
                else if (token.Text == "+")
                {
                    if (this.Result.Count > 0)
                    {
                        result = this.Result[0];
                        for (int i = 1; i < this.Result.Count; i++)
                        {
                            result = result.Operation(this.Result[i], OperationType.Plus);
                        }
                    }
                }
                else if (token.Text == "<") //min
                {
                    if (this.Result.Count > 0)
                    {
                        result = this.Result[0];

                        for (int i = 0; i < this.Result.Count; i++)
                        {
                            Bool b = (Bool)this.Result[i].Operation(result, OperationType.Less);
                            if (b.Result)
                                result = this.Result[i];
                        }
                    }
                }
                else if (token.Text == ">") //max
                {
                    if (this.Result.Count > 0)
                    {
                        result = this.Result[0];

                        for (int i = 0; i < this.Result.Count; i++)
                        {
                            Bool b = (Bool)this.Result[i].Operation(result, OperationType.Great);
                            if (b.Result)
                                result = this.Result[i];
                        }
                    }
                }
            }

            return result;
        }

        public List<Token> Result
        {
            get
            {
                return (List<Token>)base.Result;
            }

            set
            {
                base.Result = value;
            }
        }

        public Token Point(Token token)
        {
            Token result = null;

            if (token.TokenType == TokenType.Number)
            {
                Collection op1 = this;
                Number op2 = (Number)token;

                if (op2.Result >= 0 && op2.Result < op1.Result.Count)
                {
                    result = this.Result[op2.Result];
                }
                else
                {
                    result = new Null(this.Context);
                }
            }
            else if (token.TokenType == TokenType.Collection)
            {
                Collection op1 = this;
                Collection op2 = (Collection)token;

                Collection c = new Collection(this.Context);

                foreach(Token index in op2.Result)
                {
                    if(index.TokenType == TokenType.Number)
                    {
                        Number number = (Number)index;
                        if (number.Result >= 0 && number.Result < op1.Result.Count)
                        {
                            c.Result.Add(op1.Result[number.Result]);
                        }
                        else
                        {
                            c.Result.Add(new Null(this.Context));
                        }
                    }
                }

                result = c;
            }
            else if (token.TokenType == TokenType.Name)
            {
                Collection op1 = this;
                Name op2 = (Name)token;

                if (op2.Text == "Len")
                {
                    result = new Number(this.Context, op1.Result.Count);
                }
                else
                {
                    result = new Null(this.Context);
                }
            }

            return result;
        }

        public Token Add(Token token)
        {
            Collection result = null;

            if (token.TokenType == TokenType.Collection)
            {
                Collection op1 = this;
                Collection op2 = (Collection)token;

                result = new Collection(this.Context);

                result.Result.AddRange(op1.Result);
                result.Result.AddRange(op2.Result);
            }
            else
            {
                Collection op1 = this;
                Token op2 = (Token)token;

                result = new Collection(this.Context);

                result.Result.AddRange(op1.Result);
                result.Result.Add(op2);
            }

            return result;
        }

        public Token AddApply(Token token)
        {
            Collection result = null;

            if (token.TokenType == TokenType.Collection)
            {
                Collection op1 = this;
                Collection op2 = (Collection)token;

                op1.Result.AddRange(op2.Result);

                result = op1;
            }
            else
            {
                Collection op1 = this;
                Token op2 = (Token)token;

                op1.Result.Add(op2);

                result = op1;
            }

            return result;
        }

        public Token Devide(Token token)
        {
            Collections result = null;

            if (token.TokenType == TokenType.Number)
            {
                //Collection op1 = this;
                //Number op2 = (Number)token;

                ///*DocArea docArea = new DocArea();
                //Area area = new Area(this.Context, docArea);
                //area.Result.Create(op1.Result, op2.Result);*/

                //NumberCollections ncs = new NumberCollections(this.Context);

                //for (int i = 0; i < op2.Result; i++)
                //{
                //    Collection nc = new Collection(this.Context);
                //    ncs.Result.Add(nc);
                //}

                //int partSize;
                
                //if(op1.Result.Count%2==0)
                //    partSize = op1.Result.Count / op2.Result;
                //else
                //    partSize = op1.Result.Count / op2.Result + 1;

                //for (int i = 0; i < op1.Result.Count; i++)
                //{
                //    ncs.Result[i / partSize].Result.Add(op1.Result[i]);
                //}

                //result = ncs;
            }
            
            return result;
        }

        public override string ToString()
        {
            StringBuilder line = new StringBuilder();
            for (int x = 0; x < this.Result.Count; x++)
            {
                if (line.Length > 0)
                    line.Append(",");

                line.Append(this.Result[x].Result.ToString());
            }

            return line.ToString();
        }
    }
}
